package mornd.test3;

import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @author: mornd
 * @dateTime: 2023/5/6 - 17:51
 * 两种代理创建时机
 */
public class Demo2 {

    /**
     * 两种代理创建时机：
     *  创建 -> (*创建代理类) 依赖注入 -> 初始化
     *      有循环依赖，实例创建后，依赖注入之前，并暂存于二级缓存中
     *
     *  创建 -> 依赖注入 -> 初始化 (*创建代理类)
     *      没有循环依赖，初始化后创建代理
     */
    public static void main(String[] args) throws Exception {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(Config.class);

        // 解析 @Configuration @Bean 注解的 BeanFactory 后者处理器
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);

        // bean 后处理器 解析 @Aspect ，产生代理
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);

        context.refresh();
        context.close();
    }

    static class Bean1 {
        public Bean1() {
            System.out.println("Bean1 构造器");
        }

        @Autowired
        public void setBean2(Bean2 bean2) {
            System.out.println("Bean1 setBean2()->" + bean2.getClass());
        }

        @PostConstruct
        public void init() {
            System.out.println("Bean1 init()");
        }

        public void foo() {
            System.out.println("bean1 foo");
        }
    }

    static class Bean2 {
        public Bean2() {
            System.out.println("Bean2 构造器");
        }

        @Autowired
        public void setBean1(Bean1 bean1) {
            System.out.println("Bean2 setBean1()->" + bean1.getClass());
        }

        @PostConstruct
        public void init() {
            System.out.println("Bean2 init()");
        }
        public void bar() {
            System.out.println("bean2 bar");
        }
    }

    @Configuration
    static class Config {
        // 低级切面
        @Bean
        public Advisor advisor(Advice advice) {
            // 切点
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut, advice);
        }

        // 通知
        @Bean
        public Advice advice() {
            return (MethodInterceptor) invocation -> {
                System.out.println("advisor before...");
                Object result = invocation.proceed();
                System.out.println("advisor after...");
                return result;
            };
        }

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }


}
